#pragma once
#include "../global/base.h"
#include "../include/image.h"
#include "./shader/shader.h"
#include "./dataStructures.h"
#include "./vao.h"
#include <stdint.h>
#define sgl GPU::getInstance()

class GPU {
public:
	static GPU* getInstance();
	GPU();
	~GPU();
	void initSurface(const uint32_t& width, const uint32_t& height, u_int32_t* buffer = nullptr);

	void clear();

	void printVAO(const uint32_t& vaoID);
	uint32_t genBuffer();
	void deleteBuffer(const uint32_t& bufferID);
	void bindBuffer(const uint32_t& bufferType, const uint32_t& bufferID);
	void bufferData(const uint32_t& bufferType, size_t dataSize, void* data);
	uint32_t genVertexArray();
	void deleteVertexArray(const uint32_t& vaoID);
	void bindVertexArray(const uint32_t& vaoID);
	void vertexAttributePointer(
		const uint32_t& binding,
		const uint32_t& itemSize,
		const uint32_t& stride,
		const uint32_t& offset);

	void useProgram(Shader* shader);

	void drawElement(const uint32_t& drawMode, const uint32_t& first, const uint32_t& count);
private:
	void vertexShaderStage(
		std::vector<VsOutput>& vsOutputs,
		const VertexArrayObject* vao,
		const BufferObject* ebo,
		const uint32_t first,
		const uint32_t count);

	void perspectiveDivision(VsOutput& vsOutput);
	void screenMapping(VsOutput& vsOutput);	
private:
	static GPU* mInstance;
    
	uint32_t* mFrameBuffer{ nullptr };
	//VBO/EBO
	uint32_t mCurrentVBO{ 0 };
	uint32_t mCurrentEBO{ 0 };
	uint32_t mBufferCounter{ 0 };
	std::map<uint32_t, BufferObject*> mBufferMap;

	//VAO
	uint32_t mCurrentVAO{ 0 };
	uint32_t mVaoCounter{ 0 };
	std::map<uint32_t, VertexArrayObject*> mVaoMap;

	Shader* mShader{ nullptr };
	math::mat4f mScreenMatrix;
	uint32_t _width;
	uint32_t _height;
};